"""
API路由模块
"""

import asyncio
from datetime import datetime
import json
from typing import Dict
import uuid
from fastapi import APIRouter, HTTPException, Query, Request, Response
from fastapi.responses import JSONResponse, StreamingResponse

from ..config.settings import settings
from ..models.schemas import (
    HealthResponse,
)
from ..utils.logger import get_logger
from ..service.device import get_device_list as svc_get_device_list, control_device as svc_control_device

# Connected clients for session management
connected_clients: Dict[str, Dict] = {}

# MCP Protocol Version - Support 2025-03-26 Streamable HTTP transport
MCP_PROTOCOL_VERSION = "2025-03-26"

# MCP Tools
MCP_TOOLS = [
    {
        "name": "get_device_list",
        "description": "查询设备列表。输入场地名称、设备类型、设备状态，返回设备列表。设备状态必填。",
        "inputSchema": {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "设备列表查询参数",
            "description": "查询设备列表所需的参数",
            "properties": {
                "place_name": {
                    "type": "string",
                    "title": "场地名称",
                    "description": "场地名称，例如：211 410",
                    "minLength": 1,
                },
                "device_type": {
                    "type": "string",
                    "title": "设备类型",
                    "description": "设备类型，例如：空调、照明",
                    "minLength": 1,
                },
                "state": {
                    "type": "string",
                    "title": "设备状态",
                    "description": "设备状态，例如：运行中，断电",
                    "minLength": 1,
                },
            },
            "required": ["state"],
            "additionalProperties": False,
        },
    },
    {
        "name": "control_device",
        "description": "控制设备。输入设备编号数组、设备状态，控制设备。",
        "inputSchema": {
            "$schema": "http://json-schema.org/draft-07/schema#",
            "type": "object",
            "title": "控制设备参数",
            "description": "控制设备所需的参数",
            "properties": {
                "device_nos": {
                    "type": "array",
                    "title": "设备编号",
                    "description": "设备编号数组",
                    "minLength": 1,
                },
                "state": {
                    "type": "string",
                    "title": "设备状态",
                    "description": "设备状态，例如：运行中，断电",
                    "minLength": 1,
                },
            },
            "required": ["device_nos", "state"],
            "additionalProperties": False,
        },
    },
]

logger = get_logger(__name__)

# 创建路由器
router = APIRouter()


@router.get("/")
async def root():
    return {
        "name": "IOT MCP Server",
        "version": "1.0.0",
        "status": "running",
        "mcp_endpoint": "/mcp",
        "protocol_version": MCP_PROTOCOL_VERSION,
        "transport": "Streamable HTTP (2025-03-26)",
        "tools": MCP_TOOLS,
    }


@router.get("/api/devices")
async def get_devices_api(
    device_type: str = Query("", description="设备类型，例如：空调、照明"),
    place_name: str = Query("", description="场地名称，例如：211 410"),
    state: str = Query("", description="设备状态，例如：运行中，断电")
):
    """HTTP GET 端点：获取设备列表
    
    参数：
        device_type: 设备类型（可选）
        place_name: 场地名称（可选）
        state: 设备状态（可选）
        
    返回：
        JSON 格式的设备列表
    """
    try:
        # 调用设备服务获取设备列表
        devices = svc_get_device_list(
            device_type=device_type,
            place_name=place_name,
            state=state
        )
        
        # 转换为字典格式
        device_list = []
        for device in devices:
            device_dict = {
                "device_no": device.device_no,
                "device_name": device.device_name,
                "device_type": device.device_type,
                "place_id": device.place_id,
                "place_name": device.place_name,
                "is_physics": device.is_physics,
                "is_show": device.is_show,
                "state": device.state
            }
            device_list.append(device_dict)
        
        return {
            "success": True,
            "count": len(device_list),
            "devices": device_list,
            "filters": {
                "device_type": device_type,
                "place_name": place_name,
                "state": state
            }
        }
        
    except Exception as e:
        logger.error(f"获取设备列表失败: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"获取设备列表失败: {str(e)}"
        )


@router.post("/api/devices/control")
async def control_devices_api(
    request: Request
):
    """HTTP POST 端点：控制设备
    
    请求体：
        {
            "device_nos": ["设备编号1", "设备编号2"],
            "state": "目标状态"
        }
        
    返回：
        JSON 格式的控制结果
    """
    try:
        # 解析请求体
        body = await request.json()
        device_nos = body.get("device_nos", [])
        state = body.get("state", "")
        
        # 参数验证
        if not device_nos:
            raise HTTPException(status_code=400, detail="设备编号列表不能为空")
        if not state:
            raise HTTPException(status_code=400, detail="目标状态不能为空")
        
        logger.info(f"🔧 控制设备请求: {device_nos} -> {state}")
        
        # 导入设备控制服务
        from ..service.device import control_device
        
        # 调用设备控制服务
        results = await control_device(device_nos=device_nos, state=state)
        
        # 分析结果
        success_count = sum(1 for r in results if r.startswith("✅"))
        fail_count = sum(1 for r in results if r.startswith("❌"))
        
        return {
            "success": True,
            "message": f"设备控制完成: {success_count} 成功, {fail_count} 失败",
            "results": results,
            "summary": {
                "total": len(device_nos),
                "success": success_count,
                "failed": fail_count
            }
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"控制设备失败: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"控制设备失败: {str(e)}"
        )


@router.get(
    "/health",
    response_model=HealthResponse,
    summary="健康检查",
    description="检查API服务状态和模型加载状态",
)
async def health_check():
    """健康检查端点"""

    return HealthResponse(status="healthy", version=settings.app_version)


@router.get("/schema/tools")
async def get_tools_schema():
    return {
        "tools": MCP_TOOLS,
        "schema_version": "http://json-schema.org/draft-07/schema#",
    }


# MCP Streamable HTTP Transport Endpoints (2025-03-26 spec)
@router.options("/mcp")
async def mcp_options():
    """Handle CORS preflight for /mcp endpoint"""
    return JSONResponse(
        {},
        headers={
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
            "Access-Control-Allow-Headers": "Content-Type, Authorization, Mcp-Session-Id",
        },
    )


@router.get("/mcp")
async def mcp_endpoint_get(request: Request):
    """MCP Streamable HTTP Endpoint - GET for SSE connection (optional)"""
    # Generate session ID for this connection
    session_id = str(uuid.uuid4())
    logger.info(f"🔗 New MCP GET connection established - Session ID: {session_id}")

    # Store client connection info
    connected_clients[session_id] = {
        "connected_at": datetime.now().isoformat(),
        "user_agent": request.headers.get("user-agent", ""),
        "client_ip": request.client.host if request.client else "unknown",
        "initialized": False,
        "protocol_version": MCP_PROTOCOL_VERSION,
    }

    async def generate_events():
        try:
            # Keep connection alive with periodic pings
            while True:
                await asyncio.sleep(30)  # Send ping every 30 seconds
                yield f'event: ping\ndata: {{"timestamp": "{datetime.now().isoformat()}"}}\n\n'

        except asyncio.CancelledError:
            logger.info(f"🔌 MCP GET connection closed - Session ID: {session_id}")
            # Clean up client connection
            if session_id in connected_clients:
                del connected_clients[session_id]
        except Exception as e:
            logger.error(f"❌ MCP GET error for session {session_id}: {e}")
            # Clean up client connection
            if session_id in connected_clients:
                del connected_clients[session_id]

    return StreamingResponse(
        generate_events(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Headers": "*",
            "X-Accel-Buffering": "no",  # Disable nginx buffering
            "Mcp-Session-Id": session_id,  # Return session ID in header
        },
    )


@router.post("/mcp")
async def mcp_endpoint_post(request: Request):
    """MCP Streamable HTTP Endpoint - POST for JSON-RPC messages"""
    request_id = None
    try:
        data = await request.json()

        # Validate JSON-RPC 2.0 format
        if not isinstance(data, dict) or data.get("jsonrpc") != "2.0":
            raise HTTPException(status_code=400, detail="Invalid JSON-RPC 2.0 message")

        method = data.get("method")
        params = data.get("params", {})
        request_id = data.get("id")

        if not method:
            raise HTTPException(status_code=400, detail="Method is required")

        logger.info(f"📨 Received MCP request: {method} (ID: {request_id})")

        # Handle initialization - no session ID required for this
        if method == "initialize":
            client_capabilities = params.get("capabilities", {})
            client_protocol_version = params.get(
                "protocolVersion", MCP_PROTOCOL_VERSION
            )
            client_info = params.get("clientInfo", {})

            logger.info(
                f"🚀 Initialize request - Client Protocol: {client_protocol_version}"
            )
            logger.info(f"📱 Client Info: {client_info}")

            # Generate new session ID for this client
            session_id = str(uuid.uuid4())

            # Store session info
            connected_clients[session_id] = {
                "connected_at": datetime.now().isoformat(),
                "user_agent": request.headers.get("user-agent", ""),
                "client_ip": request.client.host if request.client else "unknown",
                "initialized": False,
                "protocol_version": client_protocol_version,
            }

            # Accept the client's protocol version or use our default
            accepted_version = (
                client_protocol_version
                if client_protocol_version
                else MCP_PROTOCOL_VERSION
            )

            response = {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {
                    "protocolVersion": accepted_version,
                    "serverInfo": {
                        "name": settings.app_name,
                        "version": settings.app_version,
                        "description": settings.app_description,
                    },
                    "capabilities": {
                        "tools": {},  # Server supports tools
                        "logging": {},  # Server supports logging
                    },
                },
            }

            # Return response with Mcp-Session-Id header
            logger.info(
                f"✅ Initialize response sent - Protocol: {accepted_version}, Session: {session_id}"
            )
            return JSONResponse(
                response,
                headers={
                    "Mcp-Session-Id": session_id,
                    "Access-Control-Allow-Origin": "*",
                },
            )

        # For all other methods, require session ID
        session_id = request.headers.get("mcp-session-id")
        if not session_id:
            logger.error("❌ Missing Mcp-Session-Id header for non-initialize request")
            return JSONResponse(
                {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "error": {
                        "code": -32000,
                        "message": "Bad Request: No valid session ID provided",
                    },
                },
                status_code=400,
            )

        # Validate session exists
        if session_id not in connected_clients:
            logger.error(f"❌ Invalid session ID: {session_id}")
            return JSONResponse(
                {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "error": {"code": -32000, "message": "Invalid session ID"},
                },
                status_code=404,  # Use 404 for invalid session as per spec
            )

        logger.info(f"📨 Processing message for session: {session_id}")

        # Handle tool listing
        if method == "tools/list":
            logger.info("📋 Tools list requested")
            response = {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {"tools": MCP_TOOLS},
            }
            return JSONResponse(response)
        # 新增 prompts/list 支持
        elif method == "prompts/list":
            logger.info("📋 Prompts list requested")
            response = {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {
                    "prompts": [
                        {
                            "name": "查询设备列表",
                            "title": "查询设备列表",
                            "description": "查询指定场所、指定类型、指定状态的设备列表",
                            "prompt": "查找当前还在运行的设备",
                        },
                        {
                            "name": "控制设备",
                            "title": "控制设备",
                            "description": "控制设备",
                            "prompt": "把所有开着的灯都关掉",
                        },
                    ]
                },
            }
            return JSONResponse(response)
        # 新增 resources/list 支持
        elif method == "resources/list":
            logger.info("📋 Resources list requested")
            response = {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {"resources": []},  # 返回空数组，而不是带empty的对象
            }
            return JSONResponse(response)
        # 新增 resources/templates/list 支持
        elif method == "resources/templates/list":
            logger.info("📋 Resources templates list requested")
            response = {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {
                    "templates": [
                        {
                            "id": "query_device_list_template",
                            "name": "query_device_list_template",
                            "title": "查询设备列表模板",
                            "description": "快速查询指定场所、指定类型、指定状态的设备列表",
                            "content": "查询{place_name}、{device_type}、{state}的设备列表",
                        },
                        {
                            "id": "control_device_template",
                            "name": "control_device_template",
                            "title": "控制设备模板",
                            "description": "控制设备",
                            "content": "控制{device_nos}、{state}的设备",
                        },
                    ]
                },
            }
            return JSONResponse(response)
        # Handle tool execution
        elif method == "tools/call":
            tool_name = params.get("name")
            arguments = params.get("arguments", {})

            if not tool_name:
                raise HTTPException(status_code=400, detail="Tool name is required")

            logger.info(f"🔧 Executing tool: {tool_name}")
            logger.info(f"📋 Arguments: {arguments}")

            # Execute the appropriate tool
            try:
                # Map tool names with hyphens to underscores for internal functions
                if tool_name == "get_device_list":
                    content = await get_device_list_validated(arguments)
                elif tool_name == "control_device":
                    content = await control_device_validated(arguments)
                else:
                    content = [{"type": "text", "text": f"❌ 未知工具: {tool_name}"}]

                response = {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "result": {"content": content, "isError": False},
                }
                logger.info(f"✅ Tool {tool_name} executed successfully")

            except Exception as tool_error:
                logger.error(f"❌ Tool execution error: {tool_error}")
                response = {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "result": {
                        "content": [
                            {
                                "type": "text",
                                "text": f"❌ 工具执行失败: {str(tool_error)}",
                            }
                        ],
                        "isError": True,
                    },
                }

            return JSONResponse(response)

        # Handle notifications (no response required)
        elif method and method.startswith("notifications/"):
            notification_type = method.replace("notifications/", "")
            logger.info(f"📢 Received notification: {notification_type}")

            # Process notification but don't send response
            if notification_type == "initialized":
                logger.info(
                    "🎉 Client initialized successfully - MCP handshake complete!"
                )
                # Mark session as fully initialized
                if session_id in connected_clients:
                    connected_clients[session_id]["initialized"] = True

            # Notifications should return 202 Accepted according to MCP spec
            return Response(status_code=202)  # Accepted

        # Handle ping requests
        elif method == "ping":
            response = {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {"timestamp": datetime.now().isoformat(), "status": "alive"},
            }
            return JSONResponse(response)

        # Unknown method
        else:
            logger.warning(f"⚠️ Unknown method: {method}")
            error_response = {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {
                    "code": -32601,
                    "message": "Method not found",
                    "data": {"method": method},
                },
            }
            return JSONResponse(error_response, status_code=404)

    except json.JSONDecodeError:
        logger.error("❌ Invalid JSON in request")
        return JSONResponse(
            {
                "jsonrpc": "2.0",
                "id": None,
                "error": {"code": -32700, "message": "Parse error"},
            },
            status_code=400,
        )
    except Exception as e:
        logger.error(f"❌ Unexpected error: {e}")
        return JSONResponse(
            {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {
                    "code": -32603,
                    "message": "Internal error",
                    "data": {"error": str(e)},
                },
            },
            status_code=500,
        )


@router.delete("/mcp")
async def mcp_endpoint_delete(request: Request):
    """MCP Streamable HTTP Endpoint - DELETE for session termination"""
    session_id = request.headers.get("mcp-session-id")

    if not session_id:
        return JSONResponse({"error": "Missing Mcp-Session-Id header"}, status_code=400)

    if session_id in connected_clients:
        del connected_clients[session_id]
        logger.info(f"🗑️ Session terminated: {session_id}")
        return Response(status_code=200)
    else:
        return JSONResponse({"error": "Invalid session ID"}, status_code=404)


# 新增 /sse 路由，兼容部分客户端
@router.get("/sse")
async def sse_endpoint():
    async def event_generator():
        while True:
            await asyncio.sleep(30)
            yield f"data: ping {datetime.now().isoformat()}\n\n"

    return StreamingResponse(event_generator(), media_type="text/event-stream")


async def get_device_list_validated(args: dict) -> list:
    try:
        place_name = args.get("place_name", "").strip()
        device_type = args.get("device_type", "").strip()
        state = args.get("state", "").strip()
        logger.info(f"🔍 查询设备参数: {place_name} {device_type} {state}")
        errors = []
        if not state:
            errors.append("设备状态不能为空")
        if errors:
            error_text = "❌ **参数验证失败:**\n" + "\n".join(
                f"{i+1}. {err}" for i, err in enumerate(errors)
            )
            return [{"type": "text", "text": error_text}]
        # 查询服务
        device_info_list = await svc_get_device_list(
            device_type=device_type, place_name=place_name, state=state
        )
        if device_info_list:
            text = f"📊 找到 **{len(device_info_list)}** 个设备:\n\n"
            for device_info in device_info_list:
                text += f"设备编号: {device_info.device_no}\n设备名称: {device_info.device_name}\n设备类型: {device_info.device_type}\n设备位置: {device_info.place_name}\n"
                text += "\n\n"
            return [{"type": "text", "text": text}]
        else:
            return [
                {
                    "type": "text",
                    "text": f"❌ 未找到的设备 ({place_name} {device_type} {state})",
                }
            ]
    except Exception as e:
        logger.error(f"❌ 查询设备失败: {repr(e)}")
        return [{"type": "text", "text": f"❌ **查询失败:** {repr(e)}"}]


async def control_device_validated(args: dict) -> list:
    device_nos = args.get("device_nos", [])
    state = args.get("state", "").strip()
    
    logger.info(f"🔍 控制设备参数: {device_nos} {state}")
    
    # 参数验证
    errors = []
    if not device_nos:
        errors.append("设备编号列表不能为空")
    if not state:
        errors.append("目标状态不能为空")
    
    if errors:
        error_text = "❌ **参数验证失败:**\n" + "\n".join(
            f"{i+1}. {err}" for i, err in enumerate(errors)
        )
        return [{"type": "text", "text": error_text}]
    
    try:
        # 调用设备控制服务
        results = await svc_control_device(device_nos=device_nos, state=state)
        
        # 格式化结果
        if results:
            text = f"🔧 **设备控制结果:**\n\n"
            for result in results:
                text += f"{result}\n"
            return [{"type": "text", "text": text}]
        else:
            return [{"type": "text", "text": "❌ 设备控制失败，未返回结果"}]
            
    except Exception as e:
        logger.error(f"❌ 控制设备失败: {repr(e)}")
        return [{"type": "text", "text": f"❌ **控制失败:** {repr(e)}"}]


# 注意：异常处理器需要在 FastAPI 应用实例上注册，而不是在路由器上
# 这些函数将在 main.py 中使用
def http_exception_handler(request, exc: HTTPException):
    """HTTP异常处理器"""
    logger.error(f"HTTP异常: {exc.status_code} - {exc.detail}")
    return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})


def general_exception_handler(request, exc: Exception):
    """通用异常处理器"""
    logger.error(f"未处理的异常: {type(exc).__name__} - {str(exc)}")
    return JSONResponse(status_code=500, content={"detail": "内部服务器错误"})
